﻿using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;

namespace Red.Controls.Utils
{
    /// <summary>
    /// Contains all of the configuration parameters for <see cref="SingleFileBrowserCommand"/>
    /// </summary>
    /// <example>
    /// Where "TargetProperty" is the string property that will store the selected File
    /// <code><![CDATA[
    /// <ResourceDictionary>
    ///     <utils:SingleFileBrowserCommadParam x:Key="SingleFileBrowserCommandParam" Parent="{Binding}" Property="TargetProperty"/>
    ///     <utils:SingleFileBrowserCommand x:Key="SingleFileBrowserCommand"/>
    /// </ResourceDictionary>]]>
    /// </code>
    /// </example>
    public sealed class SingleFileBrowserCommandParam : Freezable
    {
        #region Implemented Methods

        // SingleFileBrowserCommandParam inherits from Freezable so that we inherit the DataContext of the parent:
        // http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
        protected override Freezable CreateInstanceCore()
        {
            return new SingleFileBrowserCommandParam();
        }

        #endregion Implemented Methods

        #region Properties

        public static readonly DependencyProperty ParentProperty = DependencyProperty.Register( "Parent", typeof( object ), typeof( SingleFileBrowserCommandParam ) );
        public static readonly DependencyProperty CheckFileExistsProperty = DependencyProperty.Register( "CheckFileExists", typeof( bool ), typeof( SingleFileBrowserCommandParam ), new PropertyMetadata( true ) );
        public static readonly DependencyProperty CheckPathExistsProperty = DependencyProperty.Register( "CheckPathExists", typeof( bool ), typeof( SingleFileBrowserCommandParam ), new PropertyMetadata( true ) );
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( "Title", typeof( string ), typeof( SingleFileBrowserCommandParam ) );
        public static readonly DependencyProperty FilterProperty = DependencyProperty.Register( "Filter", typeof( string ), typeof( SingleFileBrowserCommandParam ) );

        public object Parent
        {
            get { return GetValue( ParentProperty ); }
            set { SetValue( ParentProperty, value ); }
        }

        public string Property { get; set; }

        public string Value
        {
            get
            {
                var property = Parent.GetType().GetProperty( Property );
                return (string)property.GetValue( Parent );
            }
            set
            {
                var property = Parent.GetType().GetProperty( Property );
                property.SetValue( Parent, value );
            }
        }

        /// <summary>
        /// Display a warning if the users select a file that does not exist
        /// </summary>
        /// <remarks>
        /// Wraps <see cref="P:System.Windows.Forms.OpenFileDialog.CheckFileExists"/>
        /// </remarks>
        /// <seealso href="https://msdn.microsoft.com/en-us/library/system.windows.forms.openfiledialog.checkfileexists.aspx">MSDN</seealso>
        public bool CheckFileExists
        {
            get { return (bool)GetValue( CheckFileExistsProperty ); }
            set { SetValue( CheckFileExistsProperty, value ); }
        }

        /// <summary>
        /// Display a warning if the users select a path that does not exist
        /// </summary>
        /// <remarks>
        /// Wraps <see cref="P:System.Windows.Forms.FileDialog.CheckPathExists"/>
        /// </remarks>
        /// <seealso href="https://msdn.microsoft.com/en-us/library/system.windows.forms.filedialog.checkpathexists.aspx">MSDN</seealso>
        public bool CheckPathExists
        {
            get { return (bool)GetValue( CheckPathExistsProperty ); }
            set { SetValue( CheckPathExistsProperty, value ); }
        }

        /// <summary>
        /// Customise the text displayed in the title bar of the file selector dialog
        /// </summary>
        /// <remarks>
        /// Wraps <see cref="P:System.Windows.Forms.FileDialog.Title"/>
        /// </remarks>
        /// <seealso href="https://msdn.microsoft.com/en-us/library/system.windows.forms.filedialog.title.aspx">MSDN</seealso>
        public string Title
        {
            get { return (string)GetValue( TitleProperty ); }
            set { SetValue( TitleProperty, value ); }
        }

        /// <summary>
        /// Customise the text displayed in the title bar of the file selector dialog
        /// </summary>
        /// <remarks>
        /// Wraps <see cref="P:System.Windows.Forms.FileDialog.Filter"/>
        /// </remarks>
        /// <seealso href="https://msdn.microsoft.com/en-us/library/system.windows.forms.filedialog.filter(v=vs.110).aspx">MSDN</seealso>
        public string Filter
        {
            get { return (string)GetValue( FilterProperty ); }
            set { SetValue( FilterProperty, value ); }
        }

        #endregion Properties
    }

    /// <summary>
    /// A Method of invoking the File Browser dialog.
    /// It also requires an associated <see cref="SingleFileBrowserCommandParam"/> instance specified as the command parameter
    /// </summary>
    /// <example>
    /// This is a continuation of the <see cref="SingleFileBrowserCommandParam"/> example
    /// <code>
    ///     <![CDATA[<Button Text="Press me!" Command="{StaticResource SingleFileBrowserCommand}" CommandParameter="{StaticResource SingleFileBrowserCommandParam}" />]]>
    /// </code>
    /// </example>
    public sealed class SingleFileBrowserCommand : ICommand
    {
        #region Events
        
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        #endregion Events

        #region Interface Methods

        public bool CanExecute( object sender )
        {
            return true;
        }

        public void Execute( object parameter )
        {
            var param = parameter as SingleFileBrowserCommandParam;
            if ( param == null )
                return;

            string directoryPath = null;
            if ( !String.IsNullOrWhiteSpace( param.Value ) )
            {
                DirectoryInfo directory = new DirectoryInfo( param.Value );
                directoryPath = directory.FullName;
            }

            var dialog = new OpenFileDialog
            {
                FileName = Path.GetFileName( param.Value ),
                InitialDirectory = directoryPath,
                Multiselect = false,
                Filter = param.Filter,
                CheckFileExists = param.CheckFileExists,
                CheckPathExists = param.CheckPathExists,
                Title = param.Title
            };

            if ( dialog.ShowDialog() == DialogResult.OK )
            {
                param.Value = dialog.FileName;
            }
        }

        #endregion Interface Methods
    }
}
